﻿
using System;
using System.Linq;
using log4net;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;

namespace SharePoint.Orm.Helpers {
	/// <summary>
	/// Collection of methods for working with <see cref="SPContentType"/>s.
	/// </summary>
	public class SPContentTypeHelper {
		private static readonly ILog _log = LogManager.GetLogger(typeof(SPContentTypeHelper));

		/// <summary>
		/// Finds a <see cref="SPFieldLink"/> or adds it to a <see cref="SPContentType"/>.
		/// </summary>
		/// <param name="contentType">The content type to find or add the field link on.</param>
		/// <param name="name">The name of the field link to find or add.</param>
		/// <param name="field">The field to link to.</param>
		/// <returns>The existing or new <see cref="SPFieldLink"/></returns>
		public static SPFieldLink FindOrAddFieldLink(SPContentType contentType, string name, SPField field) {
			if (field == null) {
				throw new ArgumentException("field cannot be null", "field");
			}
			SPFieldLink fieldLink = contentType.FieldLinks[name];
			if (fieldLink == null) {
				name = SPNameHelper.Encode(name, true);
				fieldLink = contentType.FieldLinks[name];
			}
			if (fieldLink == null) {
				_log.Info("Adding field link '" + name + "' to field '" + field.StaticName + "'");
				fieldLink = new SPFieldLink(field);
				contentType.FieldLinks.Add(fieldLink);
			}
			return fieldLink;
		}

		/// <summary>
		/// Finds a field in a <see cref="SPContentType"/>.
		/// </summary>
		/// <param name="contentType">The content type to search for the field.</param>
		/// <param name="fieldName">The title, static name, or internal name of the field to find.</param>
		/// <returns>The field or null if not found.</returns>
		public static SPField FindFieldOrDefault(SPContentType contentType, string fieldName) {
			return contentType.Fields.Cast<SPField>().FirstOrDefault(
				f => string.Equals(f.Title, fieldName, StringComparison.InvariantCultureIgnoreCase)
					|| string.Equals(f.StaticName, fieldName, StringComparison.InvariantCultureIgnoreCase)
					|| string.Equals(f.InternalName, fieldName, StringComparison.InvariantCultureIgnoreCase));
		}

		///<summary>
		/// Finds or adds a <see cref="SPWorkflowAssociation"/> to a content type.
		///</summary>
		///<param name="contentType">The content type to add the workflow association to</param>
		///<param name="name">The name of the workflow</param>
		///<param name="workflowTemplate">The template to base the workflow off of</param>
		///<param name="taskList">The task list</param>
		///<param name="historyList">The history list</param>
		///<returns>The existing or added workflow association</returns>
		public static SPWorkflowAssociation FindOrAddSiteContentTypeAssociation(SPContentType contentType, string name, SPWorkflowTemplate workflowTemplate, SPList taskList, SPList historyList) {
			SPWorkflowAssociation workflowAssociation = contentType.WorkflowAssociations
				.Cast<SPWorkflowAssociation>()
				.FirstOrDefault(wa => string.Equals(wa.Name, name, StringComparison.InvariantCultureIgnoreCase));
			if (workflowAssociation == null) {
				string taskListName = taskList.Title;
				string historyListName = historyList.Title;
				workflowAssociation =
					SPWorkflowAssociation.CreateSiteContentTypeAssociation(
						workflowTemplate,
						name,
						taskListName,
						historyListName);
				contentType.AddWorkflowAssociation(workflowAssociation);
				contentType.Update(true);
			}
			return workflowAssociation;
		}
	}
}
